package com.uniflow.controller;

import com.uniflow.common.PageResult;
import com.uniflow.common.Result;
import com.uniflow.common.ResultCode;
import com.uniflow.entity.Organization;
import com.uniflow.service.OrganizationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import java.util.List;
import java.util.Map;

/**
 * 组织架构管理控制器
 */
@RestController
@RequestMapping("/api/v1/organizations")
@Validated
@Api(tags = "组织架构管理")
public class OrganizationController {
    
    @Autowired
    private OrganizationService organizationService;
    
    /**
     * 分页查询组织列表
     */
    @GetMapping
    @PreAuthorize("hasAuthority('org:read')")
    public Result<PageResult<Organization>> getOrganizationList(
            @RequestParam(defaultValue = "1") int pageNum,
            @RequestParam(defaultValue = "10") int pageSize,
            @RequestParam(required = false) String parentId,
            @RequestParam(required = false) String keyword) {
        try {
            PageResult<Organization> result = organizationService.getOrganizationList(pageNum, pageSize, parentId, keyword);
            return Result.success(result);
        } catch (Exception e) {
            return Result.error(ResultCode.ERROR, e.getMessage());
        }
    }
    
    /**
     * 获取组织树结构
     */
    @GetMapping("/tree")
    @PreAuthorize("hasAuthority('org:read')")
    public Result<List<Organization>> getOrganizationTree() {
        try {
            List<Organization> tree = organizationService.getOrganizationTree();
            return Result.success(tree);
        } catch (Exception e) {
            return Result.error(ResultCode.QUERY_FAILED, e.getMessage());
        }
    }
    
    /**
     * 获取根组织列表
     */
    @GetMapping("/roots")
    @PreAuthorize("hasAuthority('org:read')")
    public Result<List<Organization>> getRootOrganizations() {
        try {
            List<Organization> roots = organizationService.getRootOrganizations();
            return Result.success(roots);
        } catch (Exception e) {
            return Result.error(ResultCode.QUERY_FAILED, e.getMessage());
        }
    }
    
    /**
     * 根据ID查询组织详情
     */
    @GetMapping("/{id}")
    @PreAuthorize("hasAuthority('org:read')")
    public Result<Organization> getOrganizationById(@PathVariable String id) {
        try {
            Organization organization = organizationService.getOrganizationWithManager(id);
            if (organization == null) {
                return Result.error(ResultCode.ORG_NOT_FOUND);
            }
            return Result.success(organization);
        } catch (Exception e) {
            return Result.error(ResultCode.QUERY_FAILED, e.getMessage());
        }
    }
    
    /**
     * 创建组织
     */
    @PostMapping
    @PreAuthorize("hasAuthority('org:write')")
    public Result<Organization> createOrganization(@Valid @RequestBody CreateOrganizationRequest request) {
        try {
            Organization organization = new Organization();
            organization.setName(request.getName());
            organization.setDescription(request.getDescription());
            organization.setParentId(request.getParentId());
            organization.setManagerId(request.getManagerId());
            organization.setExternalId(request.getExternalId());
            organization.setOrderNum(request.getOrderNum());
            
            Organization createdOrganization = organizationService.createOrganization(organization);
            return Result.success(createdOrganization);
        } catch (Exception e) {
            return Result.error(ResultCode.ERROR, e.getMessage());
        }
    }
    
    /**
     * 更新组织
     */
    @PutMapping("/{id}")
    @PreAuthorize("hasAuthority('org:write')")
    public Result<Organization> updateOrganization(@PathVariable String id, @Valid @RequestBody UpdateOrganizationRequest request) {
        try {
            Organization organization = new Organization();
            organization.setId(id);
            organization.setName(request.getName());
            organization.setDescription(request.getDescription());
            organization.setParentId(request.getParentId());
            organization.setManagerId(request.getManagerId());
            organization.setExternalId(request.getExternalId());
            organization.setOrderNum(request.getOrderNum());
            
            Organization updatedOrganization = organizationService.updateOrganization(organization);
            return Result.success(updatedOrganization);
        } catch (Exception e) {
            return Result.error(ResultCode.UPDATE_FAILED, e.getMessage());
        }
    }
    
    /**
     * 删除组织
     */
    @DeleteMapping("/{id}")
    @PreAuthorize("hasAuthority('org:write')")
    public Result<Void> deleteOrganization(@PathVariable String id) {
        try {
            // 检查是否有子组织
            if (organizationService.hasChildren(id)) {
                return Result.error(ResultCode.OPERATION_NOT_ALLOWED, "该组织下存在子组织，无法删除");
            }
            
            // 检查是否有用户
            int userCount = organizationService.getUserCount(id);
            if (userCount > 0) {
                return Result.error(ResultCode.OPERATION_NOT_ALLOWED, "该组织下存在用户，无法删除");
            }
            
            organizationService.deleteOrganization(id);
            return Result.success();
        } catch (Exception e) {
            return Result.error(ResultCode.DELETE_FAILED, e.getMessage());
        }
    }
    
    /**
     * 批量删除组织
     */
    @DeleteMapping
    @PreAuthorize("hasAuthority('org:write')")
    public Result<Void> deleteOrganizations(@RequestBody @NotEmpty List<String> ids) {
        try {
            // 检查每个组织是否可以删除
            for (String id : ids) {
                if (organizationService.hasChildren(id)) {
                    return Result.error(ResultCode.OPERATION_NOT_ALLOWED, "存在组织下有子组织，无法删除");
                }
                int userCount = organizationService.getUserCount(id);
                if (userCount > 0) {
                    return Result.error(ResultCode.OPERATION_NOT_ALLOWED, "存在组织下有用户，无法删除");
                }
            }
            
            organizationService.deleteOrganizations(ids);
            return Result.success();
        } catch (Exception e) {
            return Result.error(ResultCode.DELETE_FAILED, e.getMessage());
        }
    }
    
    /**
     * 获取子组织列表
     */
    @GetMapping("/{id}/children")
    @PreAuthorize("hasAuthority('org:read')")
    public Result<List<Organization>> getChildrenOrganizations(@PathVariable String id) {
        try {
            List<Organization> children = organizationService.getChildrenOrganizations(id);
            return Result.success(children);
        } catch (Exception e) {
            return Result.error(ResultCode.QUERY_FAILED, e.getMessage());
        }
    }
    
    /**
     * 获取组织路径
     */
    @GetMapping("/{id}/path")
    @PreAuthorize("hasAuthority('org:read')")
    public Result<List<Organization>> getOrganizationPath(@PathVariable String id) {
        try {
            List<Organization> path = organizationService.getOrganizationPath(id);
            return Result.success(path);
        } catch (Exception e) {
            return Result.error(ResultCode.QUERY_FAILED, e.getMessage());
        }
    }
    
    /**
     * 获取组织下的用户数量
     */
    @GetMapping("/{id}/user-count")
    @PreAuthorize("hasAuthority('org:read')")
    public Result<Integer> getUserCount(@PathVariable String id) {
        try {
            int count = organizationService.getUserCount(id);
            return Result.success(count);
        } catch (Exception e) {
            return Result.error(ResultCode.QUERY_FAILED, e.getMessage());
        }
    }
    
    /**
     * 移动组织
     */
    @PatchMapping("/{id}/move")
    @PreAuthorize("hasAuthority('org:write')")
    public Result<Void> moveOrganization(@PathVariable String id, @RequestBody MoveOrganizationRequest request) {
        try {
            organizationService.moveOrganization(id, request.getNewParentId());
            return Result.success();
        } catch (Exception e) {
            return Result.error(ResultCode.UPDATE_FAILED, e.getMessage());
        }
    }
    
    /**
     * 检查组织名称是否可用
     */
    @GetMapping("/check-name")
    public Result<Boolean> checkOrganizationName(@RequestParam String name, 
                                                  @RequestParam(required = false) String parentId,
                                                  @RequestParam(required = false) String excludeId) {
        try {
            boolean available = organizationService.isNameAvailable(name, parentId, excludeId);
            return Result.success(available);
        } catch (Exception e) {
            return Result.error(ResultCode.QUERY_FAILED, e.getMessage());
        }
    }
    
    /**
     * 获取组织统计信息
     */
    @GetMapping("/statistics")
    @PreAuthorize("hasAuthority('org:read')")
    public Result<Map<String, Object>> getOrganizationStatistics() {
        try {
            Map<String, Object> statistics = organizationService.getOrganizationStatistics();
            return Result.success(statistics);
        } catch (Exception e) {
            return Result.error(ResultCode.QUERY_FAILED, e.getMessage());
        }
    }
    
    // 内部类：请求对象
    
    public static class CreateOrganizationRequest {
        @NotBlank(message = "组织名称不能为空")
        private String name;
        
        private String description;
        private String parentId;
        private String managerId;
        private String externalId;
        private Integer orderNum;
        
        // getters and setters
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public String getDescription() { return description; }
        public void setDescription(String description) { this.description = description; }
        public String getParentId() { return parentId; }
        public void setParentId(String parentId) { this.parentId = parentId; }
        public String getManagerId() { return managerId; }
        public void setManagerId(String managerId) { this.managerId = managerId; }
        public String getExternalId() { return externalId; }
        public void setExternalId(String externalId) { this.externalId = externalId; }
        public Integer getOrderNum() { return orderNum; }
        public void setOrderNum(Integer orderNum) { this.orderNum = orderNum; }
    }
    
    public static class UpdateOrganizationRequest {
        private String name;
        private String description;
        private String parentId;
        private String managerId;
        private String externalId;
        private Integer orderNum;
        
        // getters and setters
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public String getDescription() { return description; }
        public void setDescription(String description) { this.description = description; }
        public String getParentId() { return parentId; }
        public void setParentId(String parentId) { this.parentId = parentId; }
        public String getManagerId() { return managerId; }
        public void setManagerId(String managerId) { this.managerId = managerId; }
        public String getExternalId() { return externalId; }
        public void setExternalId(String externalId) { this.externalId = externalId; }
        public Integer getOrderNum() { return orderNum; }
        public void setOrderNum(Integer orderNum) { this.orderNum = orderNum; }
    }
    
    public static class MoveOrganizationRequest {
        private String newParentId;
        
        public String getNewParentId() { return newParentId; }
        public void setNewParentId(String newParentId) { this.newParentId = newParentId; }
    }
}